// Go作者版权所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package abi

import (
	"cmd/compile/internal/base"
	"cmd/compile/internal/ir"
	"cmd/compile/internal/types"
	"cmd/internal/src"
	"fmt"
	"sync"
)

// ......................................................................
// None
// ABI实用程序的公共/导出位。
// None

// ABIParamResultInfo存储处理给定数据的结果
// 用于计算堆栈布局和寄存器分配的函数类型。对于
// 我们捕获的每个输入和输出参数是否为
// 分配的寄存器（以及哪个寄存器）或堆栈偏移量
// 对于参数if，根据
// 符合Go内部ABI规范（1.17）中的规则。
type ABIParamResultInfo struct {
	inparams          []ABIParamAssignment // 包括方法调用的接收器。不包括隐藏的闭包指针。
	outparams         []ABIParamAssignment
	offsetToSpillArea int64
	spillAreaSize     int64
	inRegistersUsed   int
	outRegistersUsed  int
	config            *ABIConfig // 启用String（）方法的步骤
}

func (a *ABIParamResultInfo) Config() *ABIConfig {
	return a.config
}

func (a *ABIParamResultInfo) InParams() []ABIParamAssignment {
	return a.inparams
}

func (a *ABIParamResultInfo) OutParams() []ABIParamAssignment {
	return a.outparams
}

func (a *ABIParamResultInfo) InRegistersUsed() int {
	return a.inRegistersUsed
}

func (a *ABIParamResultInfo) OutRegistersUsed() int {
	return a.outRegistersUsed
}

func (a *ABIParamResultInfo) InParam(i int) *ABIParamAssignment {
	return &a.inparams[i]
}

func (a *ABIParamResultInfo) OutParam(i int) *ABIParamAssignment {
	return &a.outparams[i]
}

func (a *ABIParamResultInfo) SpillAreaOffset() int64 {
	return a.offsetToSpillArea
}

func (a *ABIParamResultInfo) SpillAreaSize() int64 {
	return a.spillAreaSize
}

// ArgWidth返回所有输入所需的堆栈量
// 函数或方法的输出，包括ABI定义的参数
// 插槽和ABI为寄存器驻留参数定义的溢出插槽。
// 该名称继承自（*Type）.ArgWidth（），它将替换该名称。
func (a *ABIParamResultInfo) ArgWidth() int64 {
	return a.spillAreaSize + a.offsetToSpillArea - a.config.LocalsOffset()
}

// RegIndex将索引存储到用户使用的一组机器寄存器中
// 用于参数传递的特定体系结构上的ABI。雷金德克斯
// 值0到N-1（其中N是整数寄存器的数量
// 用于根据ABI规则传递参数）描述整数
// 登记册；值N到M（其中M是浮点数
// 使用点寄存器）。因此，如果ABI说有5个整数
// 寄存器和7个浮点寄存器，然后RegIndex值为4
// 表示第5个整数寄存器，RegIndex值为11
// 指示第7个浮点寄存器。
type RegIndex uint8

// AbiparmAssignment保存有关特定参数或
// 结果将被传递：在寄存器中（在这种情况下，“寄存器”是
// 或在堆栈上（在这种情况下，“偏移量”设置为
// 非负堆栈偏移。“寄存器”中的值是索引
// （如上所述），非架构寄存器。
type ABIParamAssignment struct {
	Type      *types.Type
	Name      types.Object // 应始终为*ir.Name，用于与特定的ssa.OpArg匹配。
	Registers []RegIndex
	offset    int32
}

// Offset返回用于寻址“a”描述的参数的堆栈偏移量。
// 如果“a”描述寄存器分配的参数，则会死机。
func (a *ABIParamAssignment) Offset() int32 {
	if len(a.Registers) > 0 {
		base.Fatalf("register allocated parameters have no offset")
	}
	return a.offset
}

// RegisterTypes返回寄存器类型的一部分
// 对应于一组参数。返回的切片
// 有多个存储空间，可能是内存类型。
func RegisterTypes(apa []ABIParamAssignment) []*types.Type {
	rcount := 0
	for _, pa := range apa {
		rcount += len(pa.Registers)
	}
	if rcount == 0 {
		// 请注意，这将捕获堆栈分配的顶级结构{}和[0]Foo。
		return make([]*types.Type, 0, 1)
	}
	rts := make([]*types.Type, 0, rcount+1)
	for _, pa := range apa {
		if len(pa.Registers) == 0 {
			continue
		}
		rts = appendParamTypes(rts, pa.Type)
	}
	return rts
}

func (pa *ABIParamAssignment) RegisterTypesAndOffsets() ([]*types.Type, []int64) {
	l := len(pa.Registers)
	if l == 0 {
		return nil, nil
	}
	typs := make([]*types.Type, 0, l)
	offs := make([]int64, 0, l)
	offs, _ = appendParamOffsets(offs, 0, pa.Type)
	return appendParamTypes(typs, pa.Type), offs
}

func appendParamTypes(rts []*types.Type, t *types.Type) []*types.Type {
	w := t.Width
	if w == 0 {
		return rts
	}
	if t.IsScalar() || t.IsPtrShaped() {
		if t.IsComplex() {
			c := types.FloatForComplex(t)
			return append(rts, c, c)
		} else {
			if int(t.Size()) <= types.RegSize {
				return append(rts, t)
			}
			// 假设32位机器上有64位整数
			// TODO endianness？高阶（符号位）字应该排在第一位吗？
			if t.IsSigned() {
				rts = append(rts, types.Types[types.TINT32])
			} else {
				rts = append(rts, types.Types[types.TUINT32])
			}
			return append(rts, types.Types[types.TUINT32])
		}
	} else {
		typ := t.Kind()
		switch typ {
		case types.TARRAY:
			for i := int64(0); i < t.NumElem(); i++ { // 0没有得到任何寄存器，加上将来的校对。
				rts = appendParamTypes(rts, t.Elem())
			}
		case types.TSTRUCT:
			for _, f := range t.FieldSlice() {
				if f.Type.Size() > 0 { // 嵌入式零宽度类型不接收寄存器
					rts = appendParamTypes(rts, f.Type)
				}
			}
		case types.TSLICE:
			return appendParamTypes(rts, synthSlice)
		case types.TSTRING:
			return appendParamTypes(rts, synthString)
		case types.TINTER:
			return appendParamTypes(rts, synthIface)
		}
	}
	return rts
}

// appendParamOffsets追加类型t的偏移量，从“at”开始，
// 输入偏移量，并返回较长的切片和下一个未使用的偏移量。
func appendParamOffsets(offsets []int64, at int64, t *types.Type) ([]int64, int64) {
	at = align(at, t)
	w := t.Width
	if w == 0 {
		return offsets, at
	}
	if t.IsScalar() || t.IsPtrShaped() {
		if t.IsComplex() || int(t.Width) > types.RegSize { // 32位上的复数和*int64
			s := w / 2
			return append(offsets, at, at+s), at + w
		} else {
			return append(offsets, at), at + w
		}
	} else {
		typ := t.Kind()
		switch typ {
		case types.TARRAY:
			for i := int64(0); i < t.NumElem(); i++ {
				offsets, at = appendParamOffsets(offsets, at, t.Elem())
			}
		case types.TSTRUCT:
			for i, f := range t.FieldSlice() {
				offsets, at = appendParamOffsets(offsets, at, f.Type)
				if f.Type.Width == 0 && i == t.NumFields()-1 {
					at++ // 最后一个字段的宽度为零
				}
			}
			at = align(at, t) // 类型大小向上舍入到其对齐方式
		case types.TSLICE:
			return appendParamOffsets(offsets, at, synthSlice)
		case types.TSTRING:
			return appendParamOffsets(offsets, at, synthString)
		case types.TINTER:
			return appendParamOffsets(offsets, at, synthIface)
		}
	}
	return offsets, at
}

// FrameOffset返回函数的帧指针相对位置
// 如果存在这样的溢出槽，则会将其输入或输出参数溢出到。
// 如果没有定义（例如，寄存器分配的输出），它将崩溃。
// 对于寄存器分配的输入，其溢出偏移量保留给morestack；
// 对于堆栈分配的输入和输出，这是它们在堆栈上的位置。
// （在ABI的未来版本中，注册常驻输入可能会丢失其定义的
// 溢出区域有助于减少烟囱尺寸。）
func (a *ABIParamAssignment) FrameOffset(i *ABIParamResultInfo) int64 {
	if a.offset == -1 {
		base.Fatalf("function parameter has no ABI-defined frame-pointer offset")
	}
	if len(a.Registers) == 0 { // 在堆栈上传递
		return int64(a.offset) - i.config.LocalsOffset()
	}
	// 登记册的溢出区
	return int64(a.offset) + i.SpillAreaOffset() - i.config.LocalsOffset()
}

// RegAmounts保存指定数量的整数/浮点寄存器。
type RegAmounts struct {
	intRegs   int
	floatRegs int
}

// ABIConfig捕获可用寄存器的数量
// 通过ABI规则进行参数传递和结果返回。
type ABIConfig struct {
	// 我们还需要什么吗？
	offsetForLocals  int64 // e、 例如，obj.（*Link）.FixedFrameSize（）--关于某些体系结构的额外链接信息。
	regAmounts       RegAmounts
	regsForTypeCache map[*types.Type]int
}

// NewABIConfig为具有
// iRegsCount整数/指针寄存器和fRegsCount浮点寄存器。
func NewABIConfig(iRegsCount, fRegsCount int, offsetForLocals int64) *ABIConfig {
	return &ABIConfig{offsetForLocals: offsetForLocals, regAmounts: RegAmounts{iRegsCount, fRegsCount}, regsForTypeCache: make(map[*types.Type]int)}
}

// Copy返回ABIConfig的副本，用于函数的编译，因此不需要使用互斥来保护对缓存的访问。
func (a *ABIConfig) Copy() *ABIConfig {
	b := *a
	b.regsForTypeCache = make(map[*types.Type]int)
	return &b
}

// LocalsOffset返回参数和结果与SP的体系结构相关的偏移量。
// 理论上，这仅用于调试；它应该已经被纳入到
// ABI相关方法的结果
func (a *ABIConfig) LocalsOffset() int64 {
	return a.offsetForLocals
}

// FloatIndexFor将r转换为浮点参数中的索引
// 登记册。如果结果为负，则输入索引实际上是针对
// 整数参数寄存器。
func (a *ABIConfig) FloatIndexFor(r RegIndex) int64 {
	return int64(r) - int64(a.regAmounts.intRegs)
}

// NumParamRegs返回用于给定类型的参数寄存器的数量，
// 不考虑现有的数量。
func (a *ABIConfig) NumParamRegs(t *types.Type) int {
	var n int
	if n, ok := a.regsForTypeCache[t]; ok {
		return n
	}

	if t.IsScalar() || t.IsPtrShaped() {
		if t.IsComplex() {
			n = 2
		} else {
			n = (int(t.Size()) + types.RegSize - 1) / types.RegSize
		}
	} else {
		typ := t.Kind()
		switch typ {
		case types.TARRAY:
			n = a.NumParamRegs(t.Elem()) * int(t.NumElem())
		case types.TSTRUCT:
			for _, f := range t.FieldSlice() {
				n += a.NumParamRegs(f.Type)
			}
		case types.TSLICE:
			n = a.NumParamRegs(synthSlice)
		case types.TSTRING:
			n = a.NumParamRegs(synthString)
		case types.TINTER:
			n = a.NumParamRegs(synthIface)
		}
	}
	a.regsForTypeCache[t] = n

	return n
}

// preAllocateParams为输入和输出获取正确的切片大小。
func (a *ABIParamResultInfo) preAllocateParams(hasRcvr bool, nIns, nOuts int) {
	if hasRcvr {
		nIns++
	}
	a.inparams = make([]ABIParamAssignment, 0, nIns)
	a.outparams = make([]ABIParamAssignment, 0, nOuts)
}

// ABIAnalyzeTypes采用可选的接收器类型、输入和输出数组，并返回ABIParamResultInfo，
// 基于给定的配置。这与config.ABIAnalyze计算的结果相同，并应用于
// 对应的方法/函数类型，但所有嵌入的参数名称都为零。
// 这是为ssagen/ssa.go:（*state）.rtcall使用的，用于缺少解析函数类型的运行时函数。
func (config *ABIConfig) ABIAnalyzeTypes(rcvr *types.Type, ins, outs []*types.Type) *ABIParamResultInfo {
	setup()
	s := assignState{
		stackOffset: config.offsetForLocals,
		rTotal:      config.regAmounts,
	}
	result := &ABIParamResultInfo{config: config}
	result.preAllocateParams(rcvr != nil, len(ins), len(outs))

	// 接受者
	if rcvr != nil {
		result.inparams = append(result.inparams,
			s.assignParamOrReturn(rcvr, nil, false))
	}

	// 投入
	for _, t := range ins {
		result.inparams = append(result.inparams,
			s.assignParamOrReturn(t, nil, false))
	}
	s.stackOffset = types.Rnd(s.stackOffset, int64(types.RegSize))
	result.inRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs

	// 输出
	s.rUsed = RegAmounts{}
	for _, t := range outs {
		result.outparams = append(result.outparams, s.assignParamOrReturn(t, nil, true))
	}
	// 溢出区域位于寄存器对齐偏移处，其大小向上舍入为寄存器对齐。
	// 理论上，TODO只能将偏移量调整到溢出数据类型所需的最小值。
	result.offsetToSpillArea = alignTo(s.stackOffset, types.RegSize)
	result.spillAreaSize = alignTo(s.spillOffset, types.RegSize)
	result.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs

	return result
}

// ABIAnalyzeFuncType采用函数类型“ft”和ABI规则描述
// “config”并分析函数以确定其参数
// 结果将被传递（在寄存器或堆栈中），返回
// 保存分析结果的ABIParamResultInfo对象。
func (config *ABIConfig) ABIAnalyzeFuncType(ft *types.Func) *ABIParamResultInfo {
	setup()
	s := assignState{
		stackOffset: config.offsetForLocals,
		rTotal:      config.regAmounts,
	}
	result := &ABIParamResultInfo{config: config}
	result.preAllocateParams(ft.Receiver != nil, ft.Params.NumFields(), ft.Results.NumFields())

	// 接受者
	// TODO（注册参数）？似乎“struct”和“fields”不再适合描述函数参数
	if ft.Receiver != nil && ft.Receiver.NumFields() != 0 {
		r := ft.Receiver.FieldSlice()[0]
		result.inparams = append(result.inparams,
			s.assignParamOrReturn(r.Type, r.Nname, false))
	}

	// 投入
	ifsl := ft.Params.FieldSlice()
	for _, f := range ifsl {
		result.inparams = append(result.inparams,
			s.assignParamOrReturn(f.Type, f.Nname, false))
	}
	s.stackOffset = types.Rnd(s.stackOffset, int64(types.RegSize))
	result.inRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs

	// 输出
	s.rUsed = RegAmounts{}
	ofsl := ft.Results.FieldSlice()
	for _, f := range ofsl {
		result.outparams = append(result.outparams, s.assignParamOrReturn(f.Type, f.Nname, true))
	}
	// 溢出区域位于寄存器对齐偏移处，其大小向上舍入为寄存器对齐。
	// 理论上，TODO只能将偏移量调整到溢出数据类型所需的最小值。
	result.offsetToSpillArea = alignTo(s.stackOffset, types.RegSize)
	result.spillAreaSize = alignTo(s.spillOffset, types.RegSize)
	result.outRegistersUsed = s.rUsed.intRegs + s.rUsed.floatRegs
	return result
}

// ABIAnalyze返回与ABIAnalyzeFuncType相同的结果，但是
// 更新所有接收器、输入和输出字段的偏移量。
// 如果setNname为true，它还将为设置Nname的帧偏移量
// 现场；这是用于编译函数和计算
// 泄漏地点。为呼叫者这样做可能会导致注册竞争
// 输出，因为它们的帧位置从伪FUNARG偏移转换
// 将其设置为零，使其看起来像自动偏移量，对调用者没有任何用处。
func (config *ABIConfig) ABIAnalyze(t *types.Type, setNname bool) *ABIParamResultInfo {
	ft := t.FuncType()
	result := config.ABIAnalyzeFuncType(ft)

	// 填写接收机、输入、结果的帧偏移
	k := 0
	if t.NumRecvs() != 0 {
		config.updateOffset(result, ft.Receiver.FieldSlice()[0], result.inparams[0], false, setNname)
		k++
	}
	for i, f := range ft.Params.FieldSlice() {
		config.updateOffset(result, f, result.inparams[k+i], false, setNname)
	}
	for i, f := range ft.Results.FieldSlice() {
		config.updateOffset(result, f, result.outparams[i], true, setNname)
	}
	return result
}

func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn, setNname bool) {
	// 除了寄存器中的返回值之外，所有内容都有一个帧主位置（如果不在寄存器中）或帧溢出位置。
	if !isReturn || len(a.Registers) == 0 {
		// 类型帧偏移不显示最小帧大小的效果。
		// 如果出现此错误，将中断stackmaps，请参见liveness/plive.go:WriteFuncMap和typebits/typebits.go:Set
		off := a.FrameOffset(result)
		fOffset := f.Offset
		if fOffset == types.BOGUS_FUNARG_OFFSET {
			if setNname && f.Nname != nil {
				f.Nname.(*ir.Name).SetFrameOffset(off)
				f.Nname.(*ir.Name).SetIsOutputParamInRegisters(false)
			}
		} else {
			base.Fatalf("field offset for %s at %s has been set to %d", f.Sym.Name, base.FmtPos(f.Pos), fOffset)
		}
	} else {
		if setNname && f.Nname != nil {
			fname := f.Nname.(*ir.Name)
			fname.SetIsOutputParamInRegisters(true)
			fname.SetFrameOffset(0)
		}
	}
}

// ......................................................................
// None
// 非公共部分。

// regString生成人类可读的RegIndex版本。
func (c *RegAmounts) regString(r RegIndex) string {
	if int(r) < c.intRegs {
		return fmt.Sprintf("I%d", int(r))
	} else if int(r) < c.intRegs+c.floatRegs {
		return fmt.Sprintf("F%d", int(r)-c.intRegs)
	}
	return fmt.Sprintf("<?>%d", r)
}

// ToString方法以人类可读的方式呈现ABIParamAssignment
// 窗体，适用于调试或单元测试。
func (ri *ABIParamAssignment) ToString(config *ABIConfig, extra bool) string {
	regs := "R{"
	offname := "spilloffset" // 偏移量用于寄存器的溢出
	if len(ri.Registers) == 0 {
		offname = "offset" // 偏移量用于内存参数
	}
	for _, r := range ri.Registers {
		regs += " " + config.regAmounts.regString(r)
		if extra {
			regs += fmt.Sprintf("(%d)", r)
		}
	}
	if extra {
		regs += fmt.Sprintf(" | #I=%d, #F=%d", config.regAmounts.intRegs, config.regAmounts.floatRegs)
	}
	return fmt.Sprintf("%s } %s: %d typ: %v", regs, offname, ri.offset, ri.Type)
}

// String方法以人类可读的格式呈现ABIParamResultInfo
// 窗体，适用于调试或单元测试。
func (ri *ABIParamResultInfo) String() string {
	res := ""
	for k, p := range ri.inparams {
		res += fmt.Sprintf("IN %d: %s\n", k, p.ToString(ri.config, false))
	}
	for k, r := range ri.outparams {
		res += fmt.Sprintf("OUT %d: %s\n", k, r.ToString(ri.config, false))
	}
	res += fmt.Sprintf("offsetToSpillArea: %d spillAreaSize: %d",
		ri.offsetToSpillArea, ri.spillAreaSize)
	return res
}

// assignState在寄存器分配过程中保持中间状态
// 对于给定的函数签名。
type assignState struct {
	rTotal      RegAmounts // 来自ABI规则的总注册金额
	rUsed       RegAmounts // 迄今为止已完全分配的参数所使用的regs
	pUsed       RegAmounts // 当前参数使用的注册表（或其中的片段）
	stackOffset int64      // 当前堆栈偏移量
	spillOffset int64      // 当前溢出偏移量
}

// align返回一个向上取整到t的对齐方式
func align(a int64, t *types.Type) int64 {
	return alignTo(a, int(t.Align))
}

// alignTo返回四舍五入到t的值，其中t必须为0或2的幂。
func alignTo(a int64, t int) int64 {
	if t == 0 {
		return a
	}
	return types.Rnd(a, int64(t))
}

// stackSlot返回参数的堆栈偏移量或
// 指定的类型。
func (state *assignState) stackSlot(t *types.Type) int64 {
	rv := align(state.stackOffset, t)
	state.stackOffset = rv + t.Width
	return rv
}

// allocateRegs返回参数或结果的寄存器索引的有序列表
// 我们刚刚决定注册可转让。寄存器的数量
// 假定needed存储在state.pUsed中。
func (state *assignState) allocateRegs(regs []RegIndex, t *types.Type) []RegIndex {
	if t.Width == 0 {
		return regs
	}
	ri := state.rUsed.intRegs
	rf := state.rUsed.floatRegs
	if t.IsScalar() || t.IsPtrShaped() {
		if t.IsComplex() {
			regs = append(regs, RegIndex(rf+state.rTotal.intRegs), RegIndex(rf+1+state.rTotal.intRegs))
			rf += 2
		} else if t.IsFloat() {
			regs = append(regs, RegIndex(rf+state.rTotal.intRegs))
			rf += 1
		} else {
			n := (int(t.Size()) + types.RegSize - 1) / types.RegSize
			for i := 0; i < n; i++ { // 展望真正的大整数
				regs = append(regs, RegIndex(ri))
				ri += 1
			}
		}
		state.rUsed.intRegs = ri
		state.rUsed.floatRegs = rf
		return regs
	} else {
		typ := t.Kind()
		switch typ {
		case types.TARRAY:
			for i := int64(0); i < t.NumElem(); i++ {
				regs = state.allocateRegs(regs, t.Elem())
			}
			return regs
		case types.TSTRUCT:
			for _, f := range t.FieldSlice() {
				regs = state.allocateRegs(regs, f.Type)
			}
			return regs
		case types.TSLICE:
			return state.allocateRegs(regs, synthSlice)
		case types.TSTRING:
			return state.allocateRegs(regs, synthString)
		case types.TINTER:
			return state.allocateRegs(regs, synthIface)
		}
	}
	base.Fatalf("was not expecting type %s", t)
	panic("unreachable")
}

// regAllocate为参数创建寄存器ABIParamAssignment对象
// 或指定类型的结果，作为最后一步（假定
// 所有安全性/适用性分析均已完成）。
func (state *assignState) regAllocate(t *types.Type, name types.Object, isReturn bool) ABIParamAssignment {
	spillLoc := int64(-1)
	if !isReturn {
		// 寄存器驻留t的溢出必须对齐，以便存储t。
		spillLoc = align(state.spillOffset, t)
		state.spillOffset = spillLoc + t.Size()
	}
	return ABIParamAssignment{
		Type:      t,
		Name:      name,
		Registers: state.allocateRegs([]RegIndex{}, t),
		offset:    int32(spillLoc),
	}
}

// stackAllocate为创建堆栈内存分配对象
// 具有指定类型的参数或结果，作为最后一步（此
// 假设所有安全性/适用性分析均已完成）。
func (state *assignState) stackAllocate(t *types.Type, name types.Object) ABIParamAssignment {
	return ABIParamAssignment{
		Type:   t,
		Name:   name,
		offset: int32(state.stackSlot(t)),
	}
}

// intUsed返回使用的整数寄存器数
// 在分配阶段内的给定点。
func (state *assignState) intUsed() int {
	return state.rUsed.intRegs + state.pUsed.intRegs
}

// floatUsed返回在某个时间消耗的浮点寄存器数
// 作业阶段内的给定点。
func (state *assignState) floatUsed() int {
	return state.rUsed.floatRegs + state.pUsed.floatRegs
}

// regassignIntegral检查整型“t”的参数/结果，以
// 确定是否可以对其进行寄存器分配。如果我们
// 可以注册分配，否则为FALSE（并更新状态
// 因此）。
func (state *assignState) regassignIntegral(t *types.Type) bool {
	regsNeeded := int(types.Rnd(t.Width, int64(types.PtrSize)) / int64(types.PtrSize))
	if t.IsComplex() {
		regsNeeded = 2
	}

	// 浮点和复数。
	if t.IsFloat() || t.IsComplex() {
		if regsNeeded+state.floatUsed() > state.rTotal.floatRegs {
			// 没有足够的注册表
			return false
		}
		state.pUsed.floatRegs += regsNeeded
		return true
	}

	// 非浮点
	if regsNeeded+state.intUsed() > state.rTotal.intRegs {
		// 没有足够的注册表
		return false
	}
	state.pUsed.intRegs += regsNeeded
	return true
}

// regassignArray处理数组类型（或某些数组中的数组组件）
// 其他封闭类型），以确定是否可以对其进行寄存器分配。
// 如果可以注册分配，则返回TRUE，否则返回FALSE。
func (state *assignState) regassignArray(t *types.Type) bool {

	nel := t.NumElem()
	if nel == 0 {
		return true
	}
	if nel > 1 {
		// 不是长度为1的数组：堆栈分配
		return false
	}
	// 访问元素
	return state.regassign(t.Elem())
}

// regassignStruct处理结构类型（或其中的结构组件）
// 其他一些封闭类型）来确定它是否可以注册
// 分配。如果可以注册分配，则返回TRUE，否则返回FALSE。
func (state *assignState) regassignStruct(t *types.Type) bool {
	for _, field := range t.FieldSlice() {
		if !state.regassign(field.Type) {
			return false
		}
	}
	return true
}

// synthOnce确保我们只创建synth*假类型一次。
var synthOnce sync.Once

// synthSlice、synthString和syncIface是合成结构类型
// 旨在捕获string/slice/interface的底层实现。
var synthSlice *types.Type
var synthString *types.Type
var synthIface *types.Type

// 安装程序执行寄存器分配实用程序的安装，制造
// 一小部分我们需要的合成类型。
func setup() {
	synthOnce.Do(func() {
		fname := types.BuiltinPkg.Lookup
		nxp := src.NoXPos
		unsp := types.Types[types.TUNSAFEPTR]
		ui := types.Types[types.TUINTPTR]
		synthSlice = types.NewStruct(types.NoPkg, []*types.Field{
			types.NewField(nxp, fname("ptr"), unsp),
			types.NewField(nxp, fname("len"), ui),
			types.NewField(nxp, fname("cap"), ui),
		})
		synthString = types.NewStruct(types.NoPkg, []*types.Field{
			types.NewField(nxp, fname("data"), unsp),
			types.NewField(nxp, fname("len"), ui),
		})
		synthIface = types.NewStruct(types.NoPkg, []*types.Field{
			types.NewField(nxp, fname("f1"), unsp),
			types.NewField(nxp, fname("f2"), unsp),
		})
	})
}

// regassign检查给定的参数类型（或某些参数中的组件）
// 复合）以确定是否可以对其进行寄存器分配。退换商品
// 如果我们可以注册分配，则为TRUE，否则为FALSE。
func (state *assignState) regassign(pt *types.Type) bool {
	typ := pt.Kind()
	if pt.IsScalar() || pt.IsPtrShaped() {
		return state.regassignIntegral(pt)
	}
	switch typ {
	case types.TARRAY:
		return state.regassignArray(pt)
	case types.TSTRUCT:
		return state.regassignStruct(pt)
	case types.TSLICE:
		return state.regassignStruct(synthSlice)
	case types.TSTRING:
		return state.regassignStruct(synthString)
	case types.TINTER:
		return state.regassignStruct(synthIface)
	default:
		base.Fatalf("not expected")
		panic("unreachable")
	}
}

// assignParamOrReturn处理给定的接收器、参数或结果
// 用于确定是否可以对字段f进行寄存器分配。
// 分析结果记录在结果中
// ABIParamResultInfo处于“状态”。
func (state *assignState) assignParamOrReturn(pt *types.Type, n types.Object, isReturn bool) ABIParamAssignment {
	state.pUsed = RegAmounts{}
	if pt.Width == types.BADWIDTH {
		base.Fatalf("should never happen")
		panic("unreachable")
	} else if pt.Width == 0 {
		return state.stackAllocate(pt, n)
	} else if state.regassign(pt) {
		return state.regAllocate(pt, n, isReturn)
	} else {
		return state.stackAllocate(pt, n)
	}
}

// ComputePadding返回“post-element”填充值列表
// 在寄存器中传递结构的情况。给
// 与结构相对应的参数赋值，它返回
// 包含每个字段的填充值，例如中的第k个元素
// 列表是字段K和以下字段之间的填充量
// 领域对于非结构（或无填充的结构）的对象
// 它返回一个零的列表。例子：
// None
// 类型小结构{
// x uint16
// y uint8
// z int32
// w int32
// }
// None
// 对于这个结构，我们将返回一个列表[0,1,0,0]，这意味着
// 我们在第二个字段后面有一个字节的填充，没有一个字节的填充
// 在任何其他字段后填充。输入参数“存储”
// 具有足够的容量来容纳
// 有问题的体系结构寄存器集。
func (pa *ABIParamAssignment) ComputePadding(storage []uint64) []uint64 {
	nr := len(pa.Registers)
	padding := storage[:nr]
	for i := 0; i < nr; i++ {
		padding[i] = 0
	}
	if pa.Type.Kind() != types.TSTRUCT || nr == 0 {
		return padding
	}
	types := make([]*types.Type, 0, nr)
	types = appendParamTypes(types, pa.Type)
	if len(types) != nr {
		panic("internal error")
	}
	off := int64(0)
	for idx, t := range types {
		ts := t.Size()
		off += int64(ts)
		if idx < len(types)-1 {
			noff := align(off, types[idx+1])
			if noff != off {
				padding[idx] = uint64(noff - off)
			}
		}
	}
	return padding
}
